#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "unistd.h"

#include "DHT11.h"

#define DHT11_PIN (25) //可通过宏定义，修改引脚

#define WaitTag(b)                \
    {                             \
        int c = 0;            \
        while (b)                 \
        {                         \
            if (c == WAIT_MAX_US) \
            {                     \
                break;            \
            }                     \
            c++;                  \
            DelayUs(1);           \
        }                         \
    }

#define SET_LOW gpio_set_level(DHT11_PIN, 0)
#define SET_HIGH gpio_set_level(DHT11_PIN, 1)
#define SET_INPUT gpio_set_direction(DHT11_PIN, GPIO_MODE_INPUT)
#define SET_OUTPUT gpio_set_direction(DHT11_PIN, GPIO_MODE_OUTPUT)
#define WAIT_MAX_US 1000 //1ms

//us延时函数，误差不能太大
void DelayUs(uint32_t nCount)
{
    usleep(nCount);
}


void DHT11_Start(void)
{
    esp_rom_gpio_pad_select_gpio(DHT11_PIN);
    SET_OUTPUT; //设置端口方向
    SET_LOW;    //拉低端口
    DelayUs(19 * 1000);
    //   vTaskDelay(19 * portTICK_RATE_MS); //持续最低18ms;

    SET_HIGH;    //释放总线
    DelayUs(30); //总线由上拉电阻拉高，主机延时30uS;
    SET_INPUT;   //设置端口方向

    WaitTag(!gpio_get_level(DHT11_PIN)); //DHT11等待80us低电平响应信号结束
    WaitTag(gpio_get_level(DHT11_PIN));  //DHT11   将总线拉高80us
}

uint8_t DHT11_ReadValue(void)
{
    uint8_t sbuf = 0;
    for (int i = 8; i > 0; i--)
    {
        sbuf <<= 1;
        WaitTag(!gpio_get_level(DHT11_PIN));
        DelayUs(30); // 延时 30us 后检测数据线是否还是高电平
        if (gpio_get_level(DHT11_PIN))
        {
            sbuf |= 1;
        }
        else
        {
            sbuf |= 0;
        }
        WaitTag(gpio_get_level(DHT11_PIN));
    }
    return sbuf;
}

uint8_t DHT11_ReadTemHum(uint8_t *buf)
{
    uint8_t check;

    buf[0] = DHT11_ReadValue();
    buf[1] = DHT11_ReadValue();
    buf[2] = DHT11_ReadValue();
    buf[3] = DHT11_ReadValue();

    check = DHT11_ReadValue();

    if (check == buf[0] + buf[1] + buf[2] + buf[3])
        return 0;
    else
        return 1;
}

uint8_t DHT11_GET(DHT11_info *inf)
{
    uint8_t DHT11Data[4] = {0};
    DHT11_Start();
    uint8_t res = DHT11_ReadTemHum(DHT11Data);
    if (res)
    {
        return 1;
    }
    inf->temp = DHT11Data[2];
    inf->humi = DHT11Data[0];
    return 0;
}
